/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.component.photo;

import cn.ac.nercis.pes.community.constant.ThumbnailSize;
import cn.ac.nercis.pes.community.model.dto.SizeDTO;
import cn.ac.nercis.pes.community.support.event.RenameCallback;
import cn.ac.nercis.pes.community.support.event.ThumbnailCallback;
import cn.ac.nercis.pes.community.utils.ControlUtils;
import cn.ac.nercis.pes.community.utils.IconUtils;
import cn.ac.nercis.pes.service.utils.FileManage;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.apache.commons.io.FileUtils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Objects;

/**
 * 缩略图自定义控件
 *
 * @author zpy
 * @version 1.0.0
 */
public class ThumbnailControl extends AnchorPane {
    private static final String DEFAULT_STYLE = "thumbnail-container";
    private static final Integer DOUBLE_CLICK_COUNT = 2;
    private final SimpleStringProperty nameProperty = new SimpleStringProperty();
    private final SimpleBooleanProperty enableSelectedProperty = new SimpleBooleanProperty(false);

    @Getter
    private File pictureFile;
    @Getter
    @Setter
    private RenameCallback<ThumbnailControl> onRenameEvent;
    @Getter
    private final ThumbnailSize size;
    @Getter
    @Setter
    private ThumbnailCallback<ThumbnailControl> onDeleteEvent;
    @Getter
    @Setter
    private StackPane dialogContainer;
    @Getter
    private Boolean selected;
    @Getter
    @Setter
    private Boolean enableModify;

    private Label nameLabel;
    private TextField nameTxt;

    public ThumbnailControl(File picture,StackPane dialogContainer) throws IOException {
        this(picture, DEFAULT_STYLE, ThumbnailSize.NORMAL,dialogContainer);
    }

    public ThumbnailControl(File picture,StackPane dialogContainer, ThumbnailSize size) throws IOException {
        this(picture, DEFAULT_STYLE, size,dialogContainer);
    }

    public ThumbnailControl(File picture, String styleCss, ThumbnailSize size,StackPane dialogContainer) throws IOException {
        this.getStyleClass().add(styleCss);
        this.enableModify = true;
        this.pictureFile = picture;
        this.size = size;
        this.dialogContainer = dialogContainer;
        nameProperty.setValue(this.pictureFile.getName());
        this.initControl();
    }

    public void setEditMode(boolean mode) {
        if (mode && this.enableModify) {
            nameLabel.setVisible(false);
            nameTxt.setVisible(true);
        } else {
            nameLabel.setVisible(true);
            nameTxt.setVisible(false);
        }
    }

    public void setEnableSelected(boolean enableSelected){
        this.enableSelectedProperty.setValue(enableSelected);
    }

    public boolean renamePhotoFile(@NonNull String newFileName) {
        File newFile = FileUtils.getFile(pictureFile.getParentFile(), newFileName);
        boolean result = pictureFile.renameTo(newFile);
        if (result) {
            nameProperty.set(newFileName);
            pictureFile = newFile;
        }
        return result;
    }

    public void setSelected(boolean selected){
        if(this.selected == selected){
            return;
        }
        this.selected = selected;
        this.getStyleClass().removeAll("thumbnail-container","thumbnail-container-selected");
        if(selected){
            this.getStyleClass().add("thumbnail-container-selected");
        }else{
            this.getStyleClass().add("thumbnail-container");
        }
    }

    private void initControl() throws IOException {
        this.selected = false;
        VBox vBox = new VBox();
        vBox.getStyleClass().add("image-box");
        vBox.setSpacing(5);
        vBox.setAlignment(Pos.CENTER);
        vBox.setMinWidth(this.size.getBodyWidth());
        vBox.setMaxWidth(this.size.getBodyWidth());
        vBox.setOnMouseClicked(this::onControlMouseClick);
        HBox imageBox = new HBox();
        imageBox.setAlignment(Pos.CENTER);
        ImageView imageView = new ImageView();
        Image seeImage = new Image(new ByteArrayInputStream(FileUtils.readFileToByteArray(pictureFile)));
        SizeDTO imageSize = ControlUtils.getPhotoSize(seeImage,this.size.getImgWidth(),this.size.getImgHeight());
        imageView.setFitHeight(imageSize.height());
        imageView.setFitWidth(imageSize.width());
        imageView.setImage(seeImage);
        HBox.setHgrow(imageView, Priority.SOMETIMES);
        imageBox.setPrefHeight(this.size.getImgHeight());
        imageBox.getChildren().add(imageView);
        imageBox.setOnMouseClicked(this::onImageMouseClick);
        VBox.setVgrow(imageBox, Priority.SOMETIMES);
        vBox.getChildren().add(imageBox);
        HBox nameBox = new HBox();
        nameBox.setAlignment(Pos.CENTER);
        nameLabel = new Label();
        nameLabel.setWrapText(true);
        nameLabel.textProperty().bind(nameProperty);
        nameLabel.managedProperty().bind(nameLabel.visibleProperty());
        nameLabel.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getButton().equals(MouseButton.PRIMARY) && mouseEvent.getClickCount() == DOUBLE_CLICK_COUNT) {
                enterEditName();
            }
        });
        nameBox.getChildren().add(nameLabel);
        nameTxt = new TextField();
        nameTxt.getStyleClass().add("pes-thumbnail-text");
        nameTxt.managedProperty().bind(nameTxt.visibleProperty());
        nameTxt.setVisible(false);
        nameTxt.setOnKeyPressed(keyEvent -> {
            if (keyEvent.getCode() == KeyCode.ENTER) {
                modifyFileName();
            } else if (keyEvent.getCode() == KeyCode.ESCAPE) {
                setEditMode(false);
            }
        });
        nameTxt.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue) {
                return;
            }
            if (Objects.nonNull(onRenameEvent)) {
                onRenameEvent.action(this,
                        FileManage.getFileNameWithoutSuffix(nameProperty.get()),
                        nameTxt.getText());
            }
        });
        nameBox.getChildren().add(nameTxt);
        vBox.getChildren().add(nameBox);

        Label delLabel = new Label();
        delLabel.getStyleClass().add("del-picture-btn");
        delLabel.setTooltip(new Tooltip("删除"));
        delLabel.setGraphic(IconUtils.getGlyph("del-picture-icon", "del-picture-icon"));
        setTopAnchor(delLabel, 0.0);
        setRightAnchor(delLabel, 0.0);
        delLabel.setOnMouseClicked((me) -> {
            if (Objects.nonNull(onDeleteEvent)) {
                onDeleteEvent.action(this);
            }
        });

        getChildren().addAll(vBox, delLabel);
    }

    private void onControlMouseClick(MouseEvent me){
        if(this.enableSelectedProperty.get()){
            this.setSelected(!this.selected);
        }
    }

    private void onImageMouseClick(MouseEvent me) {
        if(this.enableSelectedProperty.get()){
            if(me.getButton().equals(MouseButton.PRIMARY) && me.getClickCount() == DOUBLE_CLICK_COUNT){
                this.showPictureViewer();
            }
        }else{
            this.showPictureViewer();
        }
    }

    private void showPictureViewer(){
        PictureViewer viewer = new PictureViewer();
        viewer.setDialogContainer(this.dialogContainer);
        viewer.setTitle(pictureFile.getName());
        viewer.setPictureFile(this.pictureFile);
        viewer.show();
    }

    private void enterEditName() {
        nameTxt.setText(FileManage.getFileNameWithoutSuffix(nameProperty.get()));
        setEditMode(true);
        nameTxt.requestFocus();
    }

    private void modifyFileName() {
        setEditMode(false);
    }
}